Skip to content

Conversation

leodido
Copy link

@leodido leodido commented Oct 2, 2025

Description

This PR adds support for exporting Docker images to cache instead of pushing them directly to registries, enabling SLSA Level 3 compliance for Docker packages.

Problem

Currently, Docker images are pushed directly to registries during the build phase, bypassing Leeway's cache signing workflow. This prevents SLSA Level 3 compliance because:

  • Build jobs need write access to registries (can't be read-only)
  • Images can't go through the signing flow like other artifacts
  • No separation between build, sign, and push operations

Solution

Adds an optional exportToCache field to Docker package configuration:

  • false (default): Legacy behavior - push directly to registry
  • true: Export image to cache as .tar file for signing

Key Features

  • Backward Compatible: Default behavior unchanged
  • Proper Precedence: CLI flag > Environment variable > Package config
  • Bidirectional Override: Can enable OR disable export mode
  • Consistent with Leeway Patterns: Follows existing flag/env var conventions

Changes

  1. Configuration: Add exportToCache field to DockerPkgConfig
  2. Build Logic: Implement export-to-cache path that packages images as tar files
  3. Metadata: Structured metadata for exported images (names, digest, build time)
  4. CLI Flag: --docker-export-to-cache with proper precedence handling
  5. Environment Variable: LEEWAY_DOCKER_EXPORT_TO_CACHE for CI/CD
  6. Tests: Comprehensive unit tests including critical bidirectional override test
  7. Documentation: Updated README with usage examples

Usage Examples

Package Configuration:

packages:
  - name: backend
    type: docker
    config:
      dockerfile: Dockerfile
      exportToCache: true  # Enable export mode
      image:
        - registry.example.com/backend:latest

CLI Override:

# Enable for all packages
leeway build --docker-export-to-cache :backend

# Disable even if package config has it enabled
leeway build --docker-export-to-cache=false :backend

Environment Variable:

# CI/CD pipeline
export LEEWAY_DOCKER_EXPORT_TO_CACHE=true
leeway build :all

Cache Artifact Structure

When exportToCache: true, the cache artifact contains:

  • image.tar - Full Docker image (from docker save)
  • imgnames.txt - List of image tags
  • docker-export-metadata.json - Structured metadata (digest, build time, etc.)
  • metadata.yaml - Custom metadata (if configured)
  • Optional: provenance and SBOM files

Related Issue(s)

Fixes https://linear.app/ona-team/issue/CLC-2009/docker-export-mode-for-slsa-l3-compliance-leeway

Depends on #242
Depends on #245

How to test

1. Test Default Behavior (Backward Compatibility)

# Build a Docker package without exportToCache
leeway build :your-docker-package

# Should push directly to registry (legacy behavior)

2. Test Export Mode via Package Config

# In BUILD.yaml
packages:
  - name: test-image
    type: docker
    config:
      dockerfile: Dockerfile
      exportToCache: true
      image:
        - test:latest
leeway build :test-image

# Verify cache artifact contains image.tar
tar -tzf ~/.cache/leeway/test-image-*.tar.gz | grep image.tar

3. Test CLI Flag Override

# Enable export mode via CLI (overrides package config)
leeway build --docker-export-to-cache :test-image

# Disable export mode via CLI (overrides package config)
leeway build --docker-export-to-cache=false :test-image

4. Test Environment Variable

# Enable globally via env var
export LEEWAY_DOCKER_EXPORT_TO_CACHE=true
leeway build :test-image

# CLI flag should still override env var
leeway build --docker-export-to-cache=false :test-image

5. Test Metadata Extraction

# Build with export mode
leeway build --docker-export-to-cache :test-image

# Extract and verify metadata
tar -xzf ~/.cache/leeway/test-image-*.tar.gz docker-export-metadata.json
cat docker-export-metadata.json
# Should show: image_names, built_version, digest, build_time

6. Run Unit Tests

go test ./pkg/leeway/... -v -run "TestDockerPkgConfig_ExportToCache|TestBuildDocker_ExportToCache|TestDockerPackage_BuildContextOverride"

Documentation

  • leeway build --help has been updated
  • README.md has been updated with:
    • exportToCache field documentation in Docker packages section
    • SLSA L3 compliance usage note
    • CLI flag and environment variable examples
    • Reference to leeway build --help

/hold

leodido and others added 5 commits October 2, 2025 15:41
Add optional exportToCache boolean field to DockerPkgConfig to control
whether Docker images are pushed directly to registries or exported to
cache for signing.

- Default: false (maintains backward compatibility)
- When true: images exported to cache instead of pushed
- Enables SLSA Level 3 compliance workflow

Co-authored-by: Ona <[email protected]>
Add new export-to-cache path for Docker packages that exports images
as tar files instead of pushing directly to registries.

Changes:
- Add DockerExportToCache and DockerExportSet to buildOptions
- Add WithDockerExportToCache BuildOption
- Implement export logic in buildDocker function
- Branch on exportToCache flag: legacy push vs new export
- Export images to image.tar using 'docker save'
- Package tar with metadata into cache artifact
- Add override logic with proper precedence (CLI > env > config)
- Enhanced logging with structured fields

Export mode packages include:
- image.tar (full Docker image)
- imgnames.txt (image tags)
- docker-export-metadata.json (structured metadata)
- metadata.yaml (custom metadata if present)
- Optional: provenance and SBOM files

This enables Docker images to go through the same cache + signing
flow as other artifacts, closing the SLSA L3 security gap.

Co-authored-by: Ona <[email protected]>
Add CLI flag to control Docker export mode globally with proper
precedence handling following standard Leeway patterns.

Precedence order:
1. CLI flag (if explicitly set) - highest priority
2. Environment variable LEEWAY_DOCKER_EXPORT_TO_CACHE
3. Package configuration (default)

Changes:
- Add --docker-export-to-cache boolean flag
- Check flag.Changed() to detect explicit CLI usage
- Fall back to LEEWAY_DOCKER_EXPORT_TO_CACHE env var
- Pass both value and explicitlySet to BuildOption
- Update help text with examples and env var documentation

This enables:
- Per-build override: leeway build --docker-export-to-cache
- CI-level override: LEEWAY_DOCKER_EXPORT_TO_CACHE=true
- Bidirectional override (can enable OR disable)

Co-authored-by: Ona <[email protected]>
Add unit tests covering all aspects of Docker export functionality
including configuration, build behavior, and override logic.

Tests added:
- TestDockerPkgConfig_ExportToCache: validates field behavior
- TestBuildDocker_ExportToCache: integration test with mock Docker
- TestDockerPackage_BuildContextOverride: tests precedence logic
  - No override scenarios (respects package config)
  - CLI flag enables export (overrides package false)
  - CLI flag disables export (overrides package true) - CRITICAL
  - All 6 combinations of override behavior

The critical test validates bidirectional override capability,
ensuring CLI flags can both enable AND disable export mode.

Co-authored-by: Ona <[email protected]>
Update Docker packages section in README with exportToCache field
documentation and SLSA Level 3 compliance information.

Changes:
- Add exportToCache field to YAML example with inline comments
- Document default behavior (false = legacy push)
- Document export mode (true = cache for signing)
- Note override mechanisms (CLI flag and env var)
- Add SLSA L3 compliance section with usage examples
- Reference to 'leeway build --help' for details

Documentation follows existing README patterns with concise
explanations and practical examples.

Co-authored-by: Ona <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants